<?php
namespace ZyucMini\Core;

/**
 * Autoload class file 
 * 
 * 自动加载类
 * 
 * @package ZyucMini\Core
 * @author 黄凯
 */
class Autoload
{
    /**
     * 命名空间前缀到目录的映射
     * @var array
     */
    protected $prefixes = [];

    /**
     * 注册自动加载方法
     */
    public function register()
    {
        spl_autoload_register([$this, 'loadClass']);
    }

    /**
     * 添加命名空间前缀到目录的映射
     * @param string $prefix 命名空间前缀
     * @param string $base_dir 对应的基础目录
     * @param bool $prepend 是否优先检查
     */
    public function addNamespace($prefix, $base_dir, $prepend = false)
    {
        $prefix = trim($prefix, '\\') . '\\';
        $base_dir = rtrim($base_dir, DIRECTORY_SEPARATOR) . '/';
        
        if (!isset($this->prefixes[$prefix])) {
            $this->prefixes[$prefix] = [];
        }
        
        if ($prepend) {
            array_unshift($this->prefixes[$prefix], $base_dir);
        } else {
            array_push($this->prefixes[$prefix], $base_dir);
        }
    }

    /**
     * 加载类文件
     * @param string $class 完整类名
     * @return bool 是否加载成功
     */
    public function loadClass($class)
    {
        $prefix = $class;
        while (false !== $pos = strrpos($prefix, '\\')) {
            $prefix = substr($class, 0, $pos + 1);
            $relative_class = substr($class, $pos + 1);
            
            $mapped_file = $this->loadMappedFile($prefix, $relative_class);
            if ($mapped_file) {
                return $mapped_file;
            }
            
            $prefix = rtrim($prefix, '\\');
        }
        
        return false;
    }

    /**
     * 加载映射文件
     * @param string $prefix 命名空间前缀
     * @param string $relative_class 相对类名
     * @return bool 是否加载成功
     */
    protected function loadMappedFile($prefix, $relative_class)
    {
        if (!isset($this->prefixes[$prefix])) {
            return false;
        }
        
        foreach ($this->prefixes[$prefix] as $base_dir) {
            $file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
            if ($this->requireFile($file)) {
                return $file;
            }
        }
        
        return false;
    }

    /**
     * 如果文件存在则引入
     * @param string $file 文件路径
     * @return bool 文件是否存在
     */
    protected function requireFile($file)
    {
        if (file_exists($file)) {
            require $file;
            return true;
        }
        return false;
    }
}